# 一切皆函数
# 一切皆对象
# 定义类
# class Car():
#     def __init__(self, brand, type_name, category):  # self 指的是当前对象实例本身 成员属性
#         print('开始初始化')
#         # 汽车品牌
#         self.brand = brand
#         self.type_name = type_name
#         self.category = category
#
#     def run(self):  # run函数就时车的行为,对象函数（成员函数）
#         print('启动')
#         print(f'{self.brand}--{self.type_name}')
#
#     def __new__(cls, *args, **kwargs):
#         print('创建car的对象')
#         return super().__new__(cls)
#
#     def __str__(self):
#         # str 魔法函数，以后只要有print(对象)，则会自动调用str函数，并且打印str函数的返回值
#         return f'汽车的平拍：{self.brand},型号：{self.type_name},类别：{self.category}'
#
#     def __del__(self): #删除对象就会被调用
#         print('开始删除对象')
#
#
# c1 = Car('bmw', 'X3', 'SUV')
# c2 = Car('AUDI', 'Q5', 'SUV')

# 访问对象和类 在里面访问和在外面访问
# print(c1.type_name)  # 访问对象c1的属性
# c1.run()  # 访问对象c1的函数

# 魔法函数 魔术函数 __xx__ 这种类型的

# 类函数和静态函数
# 类函数
# class Person():
#     def __init__(self, name):  # 成员函数 对象函数、实例函数
#         self.name = name
#
#     def eat(self):
#         print(f'{self.name}正在吃饭')
#
#     @classmethod
#     def work(cls, other, num=100):  # 类函数
#         print('每个人都要工作')
#         print(other)
#
#     @staticmethod
#     def run():
#         print('每个人都奔跑')
#
#
# p1 = Person('张三')
# p1.eat()
# # 类函数调用
# p1.work('abc')
# Person.work('ccc')
#
# # 静态函数 调用
# p1.run()
# Person.run()

# 继承和重写
# 继承 -- 单继承
# class Animal:
#     name = '动物'
#
#     def say(self):
#         print('动物的叫声')
#
#
# class Dog(Animal):  # 子类只继承一个父类 单继承，
#     def see_home(self):
#         print('dog看家')
#
#     pass
#
#
# d = Dog()
#
# d.say()
# d.see_home()
#
# # 子类的对象 是子类类型 同时也是父类类型
# print(type(d))
# #isinstance 判断对象是否是某个类型
# print(isinstance(d, Dog))
# #issubclass 判断类是否是某个父类的子类
# print(issubclass(Dog, Animal))
# print(issubclass( Animal,Dog))

# 函数的重写 父类没有满足子类需求，父类满足一部分 怎样调 就近原则
# class Parent:
#     def __init__(self, name):
#         self.name = name
#         print('parent的init被执行了')
#
#     def say_hello(self):
#         print(f'{self.name}:hello')
#         print(f'parent:hello')
#
#
# class Son(Parent):
#     def __init__(self, name, age):
#         super().__init__(name)
#         self.age = age
#         print('son的init被执行')
#
#     def say_hello(self):
#         print(f'{self.name}:hello world')
#         print(f'sun的hello world')
#
#
# s1 = Son('张三', 10)
# s1.say_hello()

# 多继承
# 一个子类继承两个以上父类 就近 如果第一个找不到 才会找到第二个，就算第一个参数不一致也不会报错
# class Parent(object):
#     def __init__(self, name, *args, **kwargs):  # 不定长参数的好处
#         self.name = name
#         print('parent的init执行')
#
#     def test(self):
#         print('parent的test函数执行')
#
#
# class Son1(Parent):
#
#     def __init__(self, name, age, *args, **kwargs):
#         self.age = age
#         super().__init__(name, *args, **kwargs)
#         print('son1的函数执行')
#
#     def test(self):
#         print('son1的test1执行')
#
#
# class Son2(Parent):
#
#     def __init__(self, name, sex, *args, **kwargs):
#         self.sex = sex
#         super().__init__(name, *args, **kwargs)
#         print('son2的函数执行')
#
#     def test(self):
#         print('son2的test执行')
#
#
# class GranSon(Son1, Son2):  # 多继承
#     def __init__(self, name, age, sex, *args, **kwargs):
#         super().__init__(name, age, sex)
#         print('GrandSon的init执行')
#
# print(f'mro序列是：{GranSon.__mro__}')
# gs = GranSon('张三',34,'男')
# gs.test()


# 私有属性和私有函数 -- 可以为属性和函数设置私有权限 -- 即设置某个属性或函数不继承给子类 甚至不能在类的外部调用和访问
# 设置私有权限的方法  在属性名和函数名前面加两个下划线__
# 如果想修改 一般定义函数 get__xx用来获取私有属性
# class Animan(object):
#     __name = '动物'  # 私有属性 （类属性）
#
#     def __init__(self, color):
#         self.__color = color  # 私有属性
#
#     def __run(self):  # 私有函数
#         print(self.__name)
#         print('动物跑起来')
#
#     def say(self):
#         print('动物的喊叫')
#         self.__run()
#         # print(f'{self.__color}')
#
#     def set_color(self,new_color):
#         self.__color = new_color
#
#     def get_color(self):
#         return self.__color
#
#
# class Dog(Animan):
#     pass
#
#
# d = Dog('red')
# # d.__run() # 这里不能访问私有函数
# d.set_color('blue')
# d.say() # 这个函数可以访问
# # Animan.__run() # 这里也不可以访问
# col = d.get_color()
# print(col)

# 面向对象三大特征

# 封装： 将属性和方法写道类的里面的操作即为封装 封装可以为属性和方法添加私有属性
# 继承 子了默认继承父类所有的属性和方法 子类可以重写父类属性和方法
# 多态 传入不同的对象 产生不同对象的结果
# 多态
class Animal(object):
    def say(self):
        pass


class Dog(Animal):
    def say(self):
        print('ww')


class Cat(Animal):
    def say(self):
        print('mm')

d = Dog()
c = Cat()